/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { SourceFile } from 'ts-morph';
import { ITaskContext, ClassAnalysis, StringConstants, InterfaceAnalysis } from '../../..';
import { ImportManager } from '../shared/ImportManager';
import { SerializerGenerator } from './SerializerGenerator';
import SerializationPathUtil from '../../../utils/SerializationPathUtil';
import { TsMorphUtil } from '../../../utils/TsMorphUtil';

/**
 * 序列化器文件信息
 */
interface SerializerFileInfo {
  className: string; // 类名（如 "Person"）
  isGeneric: boolean;
  sourceFile: SourceFile; // ts-morph SourceFile
  importManager: ImportManager; // 独立的导入管理器
  uniqueFileName: string; // 唯一文件名（如 "model_user_PersonSerializer.ets"）
  pathPrefix: string; // 路径前缀（如 "model_user"）
}

export class TempSerializerGenerator {
  private static INSTANCE: TempSerializerGenerator = new TempSerializerGenerator();
  private readonly TEMP_SERIALIZER_DIR_NAME: string = 'tempSerializer';
  private context: ITaskContext | null = null;
  private serializerFiles: Map<string, SerializerFileInfo> = new Map();

  private constructor() { }

  static getInstance(): TempSerializerGenerator {
    return this.INSTANCE;
  }

  init(context: ITaskContext): void {
    this.context = context;
    // 确保 tempSerializer 目录存在
    const tempDir = this.getTempSerializerDir();
    if (!SerializationPathUtil.exist(tempDir)) {
      SerializationPathUtil.ensureDirSync(tempDir);
    }

    // 清空文件映射（支持多次调用init）
    this.serializerFiles.clear();
  }

  getTempSerializerDir(): string {
    return SerializationPathUtil.pathResolve(this.context!.getOutputRoot(), this.TEMP_SERIALIZER_DIR_NAME);
  }

  /**
   * 生成单个类的序列化器文件
   */
  generateSerializer(classAnalysis: ClassAnalysis | InterfaceAnalysis): void {
    const uniqueKey = this.getUniqueKey(classAnalysis);

    // 检查是否已生成，避免重复
    if (this.serializerFiles.has(uniqueKey)) {
      return;
    }

    // 生成唯一文件名
    const uniqueFileName = this.generateUniqueFileName(classAnalysis);
    const filePath = SerializationPathUtil.pathResolve(this.getTempSerializerDir(), uniqueFileName);

    // 创建独立的 SourceFile 和 ImportManager
    const sourceFile = TsMorphUtil.getProject().createSourceFile(filePath, '', { overwrite: true });
    const importManager = new ImportManager();
    importManager.setContext(this.context!);

    // 注册导入
    this.registerImports(classAnalysis, importManager);

    // 生成序列化器代码
    const serializerGenerator = new SerializerGenerator(importManager);
    const serializableGeneratorContext = serializerGenerator.generate(sourceFile, classAnalysis, this.context!);
    serializerGenerator.generateRegistration(sourceFile, serializableGeneratorContext);

    // 提取路径前缀用于别名生成
    const pathPrefix = this.extractPathPrefix(classAnalysis.sourceFilePath);

    // 保存文件信息
    this.serializerFiles.set(uniqueKey, {
      className: classAnalysis.className,
      isGeneric: classAnalysis.generics.isGeneric,
      sourceFile,
      importManager,
      uniqueFileName,
      pathPrefix
    });
  }

  private registerImports(classAnalysis: ClassAnalysis | InterfaceAnalysis, importManager: ImportManager) {
    // 注册源文件导入
    importManager.registerCustomTypeImport(classAnalysis.sourceFilePath, classAnalysis.className);
    // 拷贝源文件导入
    let sourceFile: SourceFile;
    if ((classAnalysis as ClassAnalysis).originalClass) {
      sourceFile = (classAnalysis as ClassAnalysis).originalClass!.getSourceFile();
    } else {
      sourceFile = (classAnalysis as InterfaceAnalysis).originalInterface!.getSourceFile();
    }

    sourceFile.getSourceFile().getImportDeclarations().forEach(importDecl => {
      const specifier = importDecl.getModuleSpecifierValue();
      const names = importDecl.getNamedImports().map((names) => names.getName());
      const defaultImport = importDecl.getDefaultImport();
      const originalDir = SerializationPathUtil.dirname(classAnalysis.sourceFilePath);

      const importOriginAbs = SerializationPathUtil.pathResolve(originalDir, specifier);
      if (SerializationPathUtil.exist(importOriginAbs + '.ets')) {
        // 路径存在，使用模块化路径计算
        const importOriginAbsWithExt = importOriginAbs + '.ets';
        names.forEach((name) => {
          importManager.registerCustomTypeImport(importOriginAbsWithExt, name);
        });
        if (defaultImport) {
          importManager.registerDefaultImport(importOriginAbsWithExt, defaultImport.getText());
        }
      } else {
        // 不存在该路径，说明可能为包名，暂时不动
        names.forEach((name) => {
          importManager.registerCustomImport(specifier, name);
        });
        if (defaultImport) {
          importManager.registerDefaultImport(specifier, defaultImport.getText());
        }
      }
    });
  }

  saveFile(): void {
    // 1. 保存所有序列化器文件
    for (const [_, fileInfo] of this.serializerFiles) {
      // 添加导入语句
      fileInfo.importManager.getImportDeclarations().forEach((importDeclaration) => {
        fileInfo.sourceFile.addImportDeclaration({
          moduleSpecifier: importDeclaration.specifier,
          namedImports: [...new Set(importDeclaration.names)]
        });
      });
      fileInfo.importManager.getDefaultImport().forEach((importDeclaration) => {
        fileInfo.sourceFile.addImportDeclaration({
          moduleSpecifier: importDeclaration.specifier,
          defaultImport: importDeclaration.name
        });
      });
      // 格式化代码
      fileInfo.sourceFile.formatText();
      // 保存文件
      fileInfo.sourceFile.saveSync();
    }

    // 2. 生成 index.ets 统一导出文件
    this.generateIndexFile();
  }

  private generateIndexFile(): void {
    const indexFilePath = SerializationPathUtil.pathResolve(this.getTempSerializerDir(), 'index.ets');
    const indexSourceFile = TsMorphUtil.getProject().createSourceFile(indexFilePath, '', { overwrite: true });

    // 检测类名冲突
    const classNameMap = new Map<string, SerializerFileInfo[]>();
    for (const [_, fileInfo] of this.serializerFiles) {
      const serializerName = `${fileInfo.className}${fileInfo.isGeneric ? StringConstants.SERIALIZER_FACTORY : StringConstants.SERIALIZER}`;
      if (!classNameMap.has(serializerName)) {
        classNameMap.set(serializerName, []);
      }
      classNameMap.get(serializerName)!.push(fileInfo);
    }

    // 生成导出语句
    const exportStatements: string[] = [];
    for (const [serializerName, fileInfos] of classNameMap) {
      if (fileInfos.length === 1) {
        // 无冲突：直接导出
        const fileInfo = fileInfos[0];
        const importPath = `./${fileInfo.uniqueFileName.replace('.ets', '')}`;
        exportStatements.push(`export { ${serializerName} } from '${importPath}';`);
      } else {
        // 有冲突：使用别名导出
        for (const fileInfo of fileInfos) {
          const alias = this.generateExportAlias(fileInfo);
          const importPath = `./${fileInfo.uniqueFileName.replace('.ets', '')}`;
          exportStatements.push(`export { ${serializerName} as ${alias} } from '${importPath}';`);
        }
      }
    }

    // 添加导出语句到 index.ets
    indexSourceFile.addStatements(exportStatements.join('\n'));
    indexSourceFile.formatText();
    indexSourceFile.saveSync();
  }

  /**
   * 生成导出别名（用于冲突情况）
   * 示例：model_user_PersonSerializer → ModelUserPersonSerializer
   */
  private generateExportAlias(fileInfo: SerializerFileInfo): string {
    if (!fileInfo.pathPrefix) {
      return `${fileInfo.className}${StringConstants.SERIALIZER}`;
    }

    // 将路径前缀转换为 PascalCase
    const pascalPrefix = fileInfo.pathPrefix
      .split('_')
      .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
      .join('');

    return `${pascalPrefix}${fileInfo.className}${StringConstants.SERIALIZER}`;
  }

  /**
   * 生成唯一的序列化器文件名
   * 示例：model/user/Person.ets → model_user_PersonSerializer.ets
   */
  private generateUniqueFileName(classAnalysis: ClassAnalysis | InterfaceAnalysis): string {
    const prefix = this.extractPathPrefix(classAnalysis.sourceFilePath);

    if (prefix) {
      return `${prefix}_${classAnalysis.className}${StringConstants.SERIALIZER}.ets`;
    } else {
      return `${classAnalysis.className}${StringConstants.SERIALIZER}.ets`;
    }
  }

  /**
   * 从源文件路径提取唯一前缀
   * 使用 context.calculateSourceRootToModuleRoot() 计算相对路径
   * @param sourceFilePath 源文件绝对路径
   * @returns 相对路径的父目录名称（如 "model_user"）
   */
  private extractPathPrefix(sourceFilePath: string): string {
    // 使用 context 的方法计算相对路径（自动剔除 src/main 等前缀）
    // 例如：E:\project\module\src\main\ets\model\user\Person.ets → ets/model/user/Person.ets
    const relativePath = this.context!.calculateSourceRootToModuleRoot(sourceFilePath);

    // 提取父目录路径（去掉文件名）
    const dirPath = SerializationPathUtil.dirname(relativePath);

    // 如果在根目录（例如 ets 或 .），返回空字符串
    if (dirPath === '.' || dirPath === '' || dirPath === 'ets') {
      return '';
    }

    // 去掉 ets/ 前缀（如果存在）
    let cleanedDirPath = dirPath;
    if (cleanedDirPath.startsWith('ets/') || cleanedDirPath.startsWith('ets\\')) {
      cleanedDirPath = cleanedDirPath.substring(4); // 移除 "ets/" 或 "ets\"
    }

    // 如果清理后为空，返回空字符串
    if (cleanedDirPath === '' || cleanedDirPath === '.') {
      return '';
    }

    // 转换路径分隔符为下划线，仅保留字母数字和下划线
    return cleanedDirPath.replace(/[\\/]/g, '_').replace(/[^a-zA-Z0-9_]/g, '_');
  }

  private getUniqueKey(classAnalysis: ClassAnalysis | InterfaceAnalysis): string {
    return `${classAnalysis.sourceFilePath}#${classAnalysis.className}`;
  }
}
